// utils/dingtalk_crypto.go
package utils

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"sort"
	"strings"
	"bytes"
)

// DingTalkCrypto 钉钉加解密工具
type DingTalkCrypto struct {
	Token          string
	EncodingAESKey string
	AppKey         string
	aesKey         []byte
}

// NewDingTalkCrypto 创建钉钉加解密器
func NewDingTalkCrypto(token, encodingAESKey, appKey string) *DingTalkCrypto {
	key, _ := base64.StdEncoding.DecodeString(encodingAESKey + "=")
	return &DingTalkCrypto{
		Token:          token,
		EncodingAESKey: encodingAESKey,
		AppKey:         appKey,
		aesKey:         key,
	}
}

// ValidateSignature 验证回调签名
func (d *DingTalkCrypto) ValidateSignature(signature, timestamp, nonce, echoStr string) bool {
	sign := d.GenarateSignature(timestamp, nonce, echoStr)
	return sign == signature
}

// GenarateSignature 生成签名
func (d *DingTalkCrypto) GenarateSignature(timestamp, nonce, echoStr string) string {
	strs := []string{d.Token, timestamp, nonce, echoStr}
	sort.Strings(strs)
	str := strings.Join(strs, "")
	sum := sha1.Sum([]byte(str))
	return fmt.Sprintf("%x", sum)
}

// EncryptResponse 加密响应
func (d *DingTalkCrypto) EncryptResponse(plaintext string) (string, error) {
	// 1. 构造明文
	// 钉钉要求的明文格式为: [random(16字节)][msg_len(4字节)][msg][appKey]
	randomBytes := make([]byte, 16)
	// 这里省略随机数生成
	msgLen := len(plaintext)
	lenBytes := []byte{byte(msgLen >> 24), byte(msgLen >> 16), byte(msgLen >> 8), byte(msgLen)}
	appKeyBytes := []byte(d.AppKey)

	plaintextBytes := append(randomBytes, lenBytes...)
	plaintextBytes = append(plaintextBytes, []byte(plaintext)...)
	plaintextBytes = append(plaintextBytes, appKeyBytes...)

	// 2. PKCS#7 填充
	blockSize := 32 // AES-256
	padding := blockSize - len(plaintextBytes)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	plaintextBytes = append(plaintextBytes, padtext...)

	// 3. AES-256-CBC 加密
	block, err := aes.NewCipher(d.aesKey)
	if err != nil {
		return "", err
	}

	ciphertext := make([]byte, len(plaintextBytes))
	iv := d.aesKey[:16]
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext, plaintextBytes)

	// 4. Base64 编码
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}